<?php

namespace Pay;
/**
 * Class Wxpay
 * @package pay\appPay
 * 原点 2020年5月29日17:02:10 微信APP支付
 */
class Wxpay
{
    /**
     * @var string 微信支付应用ID
     */
    private $app_id;

    /**
     * @var string 微信支付商户号
     */
    private $mch_id;

    /**
     * @var string 微信支付密钥
     */
    private $app_key;


    public function __construct(array $config = [])
    {

        $this->app_id = $config['app_id'];
        $this->mch_id = $config['mch_id'];
        $this->app_key = $config['mch_key'];
    }


    /**
     * @param array $param
     * @return bool
     * 原点 2020年5月30日09:00:27 调取支付
     */
    public function WxPay(array $param = [])
    {
        $request_data = array(
            'appid' => $this->app_id,                         #应用APPID
            'mch_id' => $this->mch_id,                        #商户号
            'trade_type' => 'APP',                            #支付类型
            'nonce_str' => $this->getRandomStr(32),  #随机字符串 不长于32位
            'body' => $param['body'],                             #商品名称
            'out_trade_no' => $param['out_trade_no'],                    #商户后台订单号
            'total_fee' => $param['total_fee'] * 100,                             #商品价格
            'spbill_create_ip' => $param['spbill_create_ip'],            #用户端实际ip
            'notify_url' => $param['notify_url'], #异步通知回调地址
        );

        // 获取签名
        $request_data['sign'] = $this->get_sign($request_data);

        // 拼装数据
        $xml_data = $this->set_xmldata($request_data);

        // 发送请求
        $res = $this->send_prePaycurl($xml_data);


        if ($res['return_code'] == 'SUCCESS' && $res['result_code'] == 'SUCCESS') {
            $two_data['appid'] = $this->app_id;  #APPID
            $two_data['partnerid'] = $this->mch_id;  #商户号
            $two_data['prepayid'] = $res['prepay_id'];  //预支付交易会话标识
            $two_data['noncestr'] = $this->getRandomStr(32);
            $two_data['timestamp'] = time();
            $two_data['package'] = "Sign=WXPay";
            $two_data['sign'] = $this->get_twosign($two_data);
            return $two_data;
        } else {
            return false;
        }
    }

    function getRandomStr($len, $special = false)
    {
        $chars = array(
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
            "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
            "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
            "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
            "3", "4", "5", "6", "7", "8", "9"
        );

        if ($special) {
            $chars = array_merge($chars, array(
                "!", "@", "#", "$", "?", "|", "{", "/", ":", ";",
                "%", "^", "&", "*", "(", ")", "-", "_", "[", "]",
                "}", "<", ">", "~", "+", "=", ",", "."
            ));
        }

        $charsLen = count($chars) - 1;
        shuffle($chars);                            //打乱数组顺序
        $str = '';
        for ($i = 0; $i < $len; $i++) {
            $str .= $chars[mt_rand(0, $charsLen)];    //随机取出一位
        }
        return $str;
    }

    //通过curl发送数据给微信接口的函数
    private function send_prePaycurl($xmlData)
    {
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $header[] = "Content-type: text/xml";
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $xmlData);
        $data = curl_exec($curl);
        if (curl_errno($curl)) {
            print curl_error($curl);
        }
        curl_close($curl);
        return $this->_xmldataparse($data);
    }

    //xml数据解析函数
    private function _xmldataparse($data)
    {
        $msg = array();
        $msg = (array)simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
        return $msg;
    }

    //生成xml格式的函数
    private function set_xmldata($data)
    {
        $xmlData = "<xml>";
        foreach ($data as $key => $value) {
            $xmlData .= "<" . $key . "><![CDATA[" . $value . "]]></" . $key . ">";
        }
        $xmlData = $xmlData . "</xml>";
        return $xmlData;
    }

    //一次签名的函数
    private function get_sign($data)
    {
        ksort($data);
        $str = '';
        foreach ($data as $key => $value) {
            $str .= !$str ? $key . '=' . $value : '&' . $key . '=' . $value;
        }
        $str .= '&key=' . $this->app_key;

        $sign = strtoupper(md5($str));
        return $sign;
    }

    //二次签名的函数
    public function get_twosign($data)
    {
        $sign_data = array(
            "appid" => $data['appid'],
            "partnerid" => $data['partnerid'],
            "prepayid" => $data['prepayid'],
            "noncestr" => $data['noncestr'],
            "timestamp" => $data['timestamp'],
            "package" => $data['package'],
        );
        return $this->get_sign($sign_data);
    }

    /**
     * @return mixed|string
     * 回调。。
     */
    public function WxNotify()
    {
        //允许从外部加载XML实体(防止XML注入攻击)
        libxml_disable_entity_loader(true);
        $receipt = file_get_contents("php://input");
        $arr = $this->fromXml($receipt);
        ksort($arr);// 对数据进行排序
        $str = $this->params_tourl($arr);//对数据拼接成字符串
        $user_sign = strtoupper(md5($str));
        if ($user_sign == $arr['sign']) {
            return $arr;
            // return '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
        } else {
            file_put_contents('notify/notify_wxpay.txt', "888", FILE_APPEND);
            return '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
        }
    }

    protected function fromXml($xml)
    {
        if (!$xml) {
            throw new InvalidArgumentException('convert to array error !invalid xml');
        }
        libxml_disable_entity_loader(true);
        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA), JSON_UNESCAPED_UNICODE), true);
    }

    // 接收post数据
    /*
    *  微信是用$GLOBALS['HTTP_RAW_POST_DATA'];这个函数接收post数据的
    */
    public function post_data()
    {
        $receipt = $_REQUEST;
        if ($receipt == null) {
            $receipt = file_get_contents("php://input");
            if ($receipt == null) {
                $receipt = $GLOBALS['HTTP_RAW_POST_DATA'];
            }
        }
        return $receipt;
    }

    //把对象转成数组
    public function object_toarray($arr)
    {
        if (is_object($arr)) {
            $arr = (array)$arr;
        }
        if (is_array($arr)) {
            foreach ($arr as $key => $value) {
                $arr[$key] = $this->object_toarray($value);
            }
        }
        return $arr;
    }


    /**
     * 格式化参数格式化成url参数
     */
    private function params_tourl($arr)
    {
        $weipay_key = $this->app_key;
        $buff = "";
        foreach ($arr as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff . '&key=' . $weipay_key;
    }

}